/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using System.Qizx.Api;
using EvaluationException = System.Qizx.Api.EvaluationException;
using Node = System.Qizx.Api.Node;
using BasicNode = System.Qizx.Xdm.BasicNode;
using NodeFilter = System.Qizx.Xdm.NodeFilter;
using System.Qizx.XQuery;
using Expression = System.Qizx.XQuery.Op.Expression;
namespace System.Qizx.XQuery.Dt
{
	
	/// <summary> Represents any node type.</summary>
	public class NodeType:XQItemType
	{
		public override string ShortName
		{
			get
			{
				return "node";
				//        int kind = nodeFilter == null ? -1 : nodeFilter.getNodeKind();
				//        if (kind < 0)
				//            return "node";
				//        return nodeKind(kind);
			}
			
		}
		// details of the node type: can be null if node()
		public NodeFilter nodeFilter;
		
		public NodeType(NodeFilter nodeFilter)
		{
			this.nodeFilter = nodeFilter;
			parent = XQType.NODE; // unless set by class Type
		}
		
		public override bool accepts(XQType valueType)
		{
			valueType = valueType.itemType();
			if (!(valueType is NodeType))
				return false;
			// TODO: too lax
			NodeFilter otherTest = ((NodeType) valueType).nodeFilter;
			return nodeFilter == null || otherTest != null && nodeFilter.Accepts(otherTest.NodeKind, null) || otherTest == null && nodeFilter.Accepts(XdmNodeType.Unknown, null);
		}
		
		public override bool encompasses(XQItemType valueType)
		{
			// System.err.println("ENCOMPASSES?");
			return accepts(valueType);
		}
		
		public override bool acceptsItem(XQItem item)
		{
			// System.err.println(this+" acceptsItem "+item);
			if (!item.IsNode)
				return false;
			try
			{
				Node node = item.GetNode(); // throws exception if not a node
				return nodeFilter == null || nodeFilter.Accepts(node);
			}
			catch (EvaluationException e)
			{
				SupportClass.WriteStackTrace(e, Console.Error);
				return false; // cannot happen due to check above
			}
		}
		
		public override string toString(BasicStaticContext ctx)
		{
			return ToString();
		}
		
		public override string ToString()
		{
			XdmNodeType kind = nodeFilter == null ? XdmNodeType.Unknown: nodeFilter.NodeKind;
			if (kind < 0)
				return "node()";
			// return nodeKind(kind) + "("+ nodeFilter + ")";
			return nodeKind(kind) + "()";
		}
		
		public override int quickCode()
		{
			return QT_UNTYPED;
		}

        public static string nodeKind(XdmNodeType kind)
		{
			switch (kind)
			{
				
				case System.Qizx.Api.XdmNodeType.Document: 
					return "document";
				
				case System.Qizx.Api.XdmNodeType.Element: 
					return "element";
				
				case System.Qizx.Api.XdmNodeType.Text: 
					return "text";
				
				case System.Qizx.Api.XdmNodeType.Comment: 
					return "comment";
				
				case System.Qizx.Api.XdmNodeType.ProcessingInstruction: 
					return "processing-instruction";
				
				case System.Qizx.Api.XdmNodeType.Attribute: 
					return "attribute";
				
				case System.Qizx.Api.XdmNodeType.Namespace: 
					return "namespace";
				
				default: 
					return "illegal node";
				
			}
		}

        static public XQItemType getTypeByKind(XdmNodeType kind)
		{
			switch (kind)
			{
				
				case System.Qizx.Api.XdmNodeType.Document: 
					return XQType.DOCUMENT;
				
				case System.Qizx.Api.XdmNodeType.Element: 
					return XQType.ELEMENT;
				
				case System.Qizx.Api.XdmNodeType.Attribute: 
					return XQType.ATTRIBUTE;
				
				case System.Qizx.Api.XdmNodeType.Text: 
					return XQType.TEXT;
				
				case System.Qizx.Api.XdmNodeType.ProcessingInstruction: 
					return XQType.PI;
				
				case System.Qizx.Api.XdmNodeType.Comment: 
					return XQType.COMMENT;
				
				case System.Qizx.Api.XdmNodeType.Namespace: 
					return XQType.NAMESPACE;
				
				default: 
					throw new System.SystemException("wrong node kind " + kind);
				
			}
		}
		
		public override XQValue convertFromObject(System.Object object_Renamed)
		{
			if (object_Renamed is BasicNode)
				return new SingleNode((BasicNode) object_Renamed);
			else if (object_Renamed == null)
				return System.Qizx.XQuery.XQValues.Empty;
			//TODO convert DOM etc ? or externally?
			else
				return invalidCast(this);
		}
		
		public override System.Object convertToObject(Expression expr, Focus focus, EvalContext context)
		{
			return expr.EvalAsNode(focus, context);
		}
		
		public override XQValue convertFromArray(System.Object object_Renamed)
		{
			if (object_Renamed is BasicNode)
				return new SingleItem((BasicNode) object_Renamed);
			if (typeof(Node[]).IsAssignableFrom(object_Renamed.GetType()))
			{
				Node[] result = (Node[]) object_Renamed;
				return new ArraySequence(result, result.Length);
			}
			return invalidCast(this);
		}
		
		public override System.Object convertToArray(XQValue value_Renamed)
		{
			return ArraySequence.expandNodes(value_Renamed);
		}
	}
}